Skip to content

fix(core-tools): resolve defensive path resolution for at-reference files and fix macOS tests#28053

Open
luisfelipe-alt wants to merge 2 commits into
google-gemini:mainfrom
luisfelipe-alt:bugfix/WT-engineer_495551283_full
Open

fix(core-tools): resolve defensive path resolution for at-reference files and fix macOS tests#28053
luisfelipe-alt wants to merge 2 commits into
google-gemini:mainfrom
luisfelipe-alt:bugfix/WT-engineer_495551283_full

Conversation

@luisfelipe-alt

@luisfelipe-alt luisfelipe-alt commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR implements a comprehensive, defensive path resolution fix for a critical production bug where filesystem tools (read_file, replace, write_file) fail with a "File not found" error when the model passes a path prefixed with @ (e.g., @policies/new-policies.txt).

Additionally, this PR resolves macOS-specific test failures in EditTool and WriteFileTool caused by path resolution mismatches (due to the /var -> /private/var symlink on macOS), sanitizes file paths by stripping null bytes to prevent potential crash vulnerabilities, and enhances test stability by generating unique session IDs in trackerTools.test.ts.

Furthermore, this PR incorporates several critical security and robustness enhancements requested during code review, including consistent @ prefix stripping, plan-mode boundary enforcement, and test isolation improvements.

Details

We implemented a centralized, defensive path resolution utility and applied targeted, platform-aware fixes to align the test environment with the production path resolution behavior:

  1. Defensive Path Resolution (packages/core/src/utils/paths.ts):

    • Implemented resolveDefensiveToolPath to strip leading @ reference prefixes if the literal path does not exist but the stripped path does.
    • Consistent @ Prefix Stripping: Updated the logic to consistently strip the @ prefix when creating new files/directories (unless a literal @-prefixed directory already exists on disk), preventing the accidental creation of literal @-prefixed folders (e.g., @src, @policies).
    • Path Alias Support: Added explicit checks for @/ and @\ prefixes to always strip the @ and leading slashes, ensuring that common path aliases are resolved correctly even when the target directory does not exist yet.
    • Null Byte Sanitization: Sanitizes file paths by stripping any null bytes (\0) at the very beginning of resolveDefensiveToolPath to prevent potential crash vulnerabilities (TypeError) in downstream synchronous file system operations.
  2. Tool Integration & Hardening:

    • ReadFileTool (packages/core/src/tools/read-file.ts): Applied resolveDefensiveToolPath in both the constructor and validateToolParamValues.
    • WriteFileTool (packages/core/src/tools/write-file.ts):
      • Applied resolveDefensiveToolPath in the constructor, validateToolParamValues, and getCorrectedFileContent (simplifying and hardening the logic by calling it directly for all paths, including absolute paths).
      • Plan-Mode Boundary Enforcement: Removed the path.isAbsolute check in getCorrectedFileContent to ensure that absolute paths in plan mode do not bypass resolveAndValidatePlanPath, strictly restricting the agent to the plans directory.
      • Plan-Mode Sanitization: Sanitizes null bytes from file paths before resolving the plan path in the constructor, validation, and content correction methods to prevent resolveToRealPath from throwing errors.
    • EditTool (packages/core/src/tools/edit.ts):
      • Applied resolveDefensiveToolPath in the constructor, validateToolParamValues, and getModifyContext.
      • Null Byte Sanitization in Fallbacks: Added explicit null byte sanitization in the absolute path fallback branches (constructor, validation, and context methods) to prevent unsanitized paths from leaking downstream.
      • Plan-Mode Sanitization: Sanitizes null bytes from file paths before resolving the plan path in the constructor, validation, and context methods to prevent resolveToRealPath from throwing errors.
    • Path Corrector (packages/core/src/utils/pathCorrector.ts): Applied resolveDefensiveToolPath at the beginning of correctPath.
  3. macOS Test Fixes & Test Isolation:

    • Mock Workspace Context (packages/core/src/test-utils/mockWorkspaceContext.ts): Updated createMockWorkspaceContext to resolve all input directories to their real paths using fs.realpathSync. This ensures that on macOS, any directory starting with /var/... is correctly resolved to /private/var/..., matching the behavior of the production code and fixing 30 failures in edit.test.ts and boundary failures in write-file.test.ts.
    • WriteFileTool Tests (packages/core/src/tools/write-file.test.ts):
      • Test Isolation: Declared rootDir and plansDir without static global initializers and initialized them with unique temporary directories using fs.mkdtempSync inside beforeEach to prevent race conditions and test interference during concurrent test execution.
      • Updated specific test cases to resolve expected paths to their real paths using resolveToRealPath before asserting.
    • EditTool Tests (packages/core/src/tools/edit.test.ts):
      • Resolved tempDir to its real path using fs.realpathSync in beforeEach to ensure all generated paths are fully resolved, fixing all remaining macOS path mismatches.
  4. Test Stability:

    • Tracker Tools Tests (packages/core/src/tools/trackerTools.test.ts): Replaced the hardcoded sessionId: 'test-session' with a dynamically generated unique session ID using Math.random() to prevent test session leakage and concurrency issues.
  5. Consolidated Test Suite (packages/core/src/tools/at-reference-resolution.test.ts):

    • Created a new consolidated test suite verifying successful path resolution, file updates, new file creation, nested subdirectory creation, path traversal blocking, and symlink loop handling across all three tools.
  6. Build Script Robustness (scripts/build.js):

    • Modified the build script to use npx --no-install npm-run-all to force using the locally installed version and bypass registry/network calls, making the build script robust in corporate environments (Corp Airlock).

Related Issues

How to Validate

Step 1: Run the modified test suites on macOS

Run the following commands on a macOS machine to verify that all tests pass successfully:

npx vitest run packages/core/src/tools/edit.test.ts
npx vitest run packages/core/src/tools/write-file.test.ts
npx vitest run packages/core/src/tools/at-reference-resolution.test.ts
npx vitest run packages/core/src/tools/trackerTools.test.ts

Expected Output: All 125+ tests pass successfully with zero failures.

Step 2: Run the test suites on Linux/Windows (Regression Check)

Run the same commands on Linux or Windows to ensure zero regressions:

npx vitest run packages/core/src/tools/write-file.test.ts packages/core/src/tools/at-reference-resolution.test.ts

Expected Output: All 63 tests pass successfully with zero failures.

Step 3: Run linting and type checking

Verify that the codebase remains fully compliant with the project's engineering standards:

npm run lint && npm run typecheck

Expected Output: Zero linting or type-checking errors.

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
    • Windows
      • npm run
      • npx
    • Linux
      • npm run
      • npx

@luisfelipe-alt luisfelipe-alt requested review from a team as code owners June 19, 2026 21:59
@github-actions github-actions Bot added the size/xl An extra large PR label Jun 19, 2026
@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

📊 PR Size: size/XL

  • Lines changed: 1116
  • Additions: +1063
  • Deletions: -53
  • Files changed: 12

@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

🛑 Action Required: Evaluation Approval

Steering changes have been detected in this PR. To prevent regressions, a maintainer must approve the evaluation run before this PR can be merged.

Maintainers:

  1. Go to the Workflow Run Summary.
  2. Click the yellow 'Review deployments' button.
  3. Select the 'eval-gate' environment and click 'Approve'.

Once approved, the evaluation results will be posted here automatically.

@luisfelipe-alt

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a robust, defensive path resolution mechanism to handle @ prefixed file paths, preventing production errors where tools fail to locate files. It also addresses platform-specific test instabilities on macOS by ensuring consistent real-path resolution and adds a new consolidated test suite to verify path handling across all filesystem tools.

Highlights

  • Defensive Path Resolution: Implemented resolveDefensiveToolPath to handle @ prefixed paths and sanitize inputs by stripping null bytes, preventing potential crashes.
  • macOS Test Fixes: Standardized path resolution using fs.realpathSync across test suites to resolve symlink mismatches (e.g., /var vs /private/var) on macOS.
  • Tool Integration: Updated ReadFileTool, WriteFileTool, EditTool, and pathCorrector to utilize the new defensive resolution and real-path validation logic.
  • Consolidated Testing: Added a comprehensive test suite for @ reference resolution and improved overall test stability by using dynamic session IDs.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces defensive path resolution and sanitization across several tools (EditTool, ReadFileTool, WriteFileTool, and pathCorrector) by implementing and utilizing resolveDefensiveToolPath and resolveToRealPath. This helps handle LLM-generated paths safely, stripping null bytes and reference prefixes (like @), and resolving symlinks. Corresponding tests have been updated or added to verify these behaviors. The reviewer pointed out a potential vulnerability in packages/core/src/tools/edit.ts where a fallback branch for absolute paths could leak unsanitized null bytes if resolveToRealPath throws an error, and suggested sanitizing the path before fallback.

Comment thread packages/core/src/tools/edit.ts
@gemini-cli gemini-cli Bot added the status/need-issue Pull requests that need to have an associated issue. label Jun 19, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces defensive path resolution and sanitization (such as stripping null bytes and handling '@' prefixes) across the EditTool, ReadFileTool, and WriteFileTool to prevent path traversal and ensure safe workspace access. The review feedback highlights a critical edge case where paths like @/ or @\ can resolve to the workspace root, and points out an inconsistency in stripping the @ prefix when creating new directories, which could lead to the accidental creation of literal @-prefixed folders. Suggestions were provided to consistently strip the prefix and update the corresponding tests.

Comment thread packages/core/src/utils/paths.ts
Comment thread packages/core/src/utils/paths.ts
Comment thread packages/core/src/tools/at-reference-resolution.test.ts
Comment thread packages/core/src/tools/at-reference-resolution.test.ts
@luisfelipe-alt

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces defensive path resolution and sanitization across several tools (EditTool, ReadFileTool, WriteFileTool) and utilities. It implements resolveDefensiveToolPath to strip null bytes and handle @ reference prefixes safely, and resolves paths to their real paths using resolveToRealPath to prevent path traversal vulnerabilities and handle symlinks gracefully. The review feedback highlights that in write-file.test.ts, rootDir and plansDir are declared as module-level variables with static paths, which can cause race conditions and test interference during concurrent test execution. The reviewer suggests initializing these variables with unique temporary directories inside beforeEach to ensure proper test isolation.

Comment thread packages/core/src/tools/write-file.test.ts Outdated
Comment thread packages/core/src/tools/write-file.test.ts Outdated
@luisfelipe-alt

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces defensive path resolution and sanitization across various tools (Edit, ReadFile, WriteFile) to prevent path traversal and null byte injection vulnerabilities, notably by implementing resolveDefensiveToolPath and resolving paths to their real paths. It also adds comprehensive tests for at-reference path resolution, null byte sanitization, and symlink loops. The feedback highlights an inconsistency in packages/core/src/tools/write-file.ts where absolute paths are not sanitized using resolveDefensiveToolPath in getCorrectedFileContent, and suggests simplifying this by calling the sanitization function directly.

Comment thread packages/core/src/tools/write-file.ts Outdated
@luisfelipe-alt

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces defensive path resolution and sanitization across file tools (such as edit, read, and write tools) to prevent path traversal, null byte injection, and accidental creation of literal '@'-prefixed directories. The feedback highlights several locations in plan-mode resolution within edit.ts and write-file.ts where raw file paths containing null bytes could still cause resolveToRealPath to throw errors, recommending that these paths be sanitized before resolving the plan path.

Comment thread packages/core/src/tools/edit.ts
Comment thread packages/core/src/tools/edit.ts
Comment thread packages/core/src/tools/edit.ts
Comment thread packages/core/src/tools/write-file.ts
Comment thread packages/core/src/tools/write-file.ts
Comment thread packages/core/src/tools/write-file.ts
@luisfelipe-alt

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces defensive path resolution and sanitization across several tools (Edit, ReadFile, WriteFile) to strip null bytes and handle '@' reference prefixes safely, accompanied by comprehensive test coverage. A critical security feedback was provided regarding a potential path traversal vulnerability in write-file.ts where absolute paths in plan mode bypass resolveAndValidatePlanPath, potentially allowing writes outside the plans directory.

Note: Security Review did not run due to the size of the PR.

Comment thread packages/core/src/tools/write-file.ts Outdated
@luisfelipe-alt

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces defensive path resolution and sanitization across core tools, including EditTool, ReadFileTool, and WriteFileTool. It implements a new utility, resolveDefensiveToolPath, to strip null bytes and safely handle @-prefixed reference paths, preventing accidental directory creation. Tests have been updated to use real paths and expanded to cover these new path resolution behaviors. No review comments were provided, so I have no feedback to address.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xl An extra large PR status/need-issue Pull requests that need to have an associated issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant